// main.cpp

#include "VBXML/VBXML.h"
using namespace ::br::com::sbVB::VBLib;

#include "VBXML/VBXML.h"
using namespace ::br::com::sbVB::VBXML;
XERCES_CPP_NAMESPACE_USE

#include <deque>
#include <iostream>
using namespace std;

void myAssert(bool shouldBeTrue)
{
	if (!shouldBeTrue)
		cout << "Assert failure" << endl;

}

void hello_tests()
{
	myAssert(getNumber3()==3);
	VBAssert(getNumber3()==3);
}


class Book
{
public:
	VBString m_title;
	VBString m_author;
	VBString m_editor;
	int m_year;

	Book(const char *title="", const char* author="", const char *editor="", int year=0)
		: m_title(title), m_author(author), m_editor(editor), m_year(year)
	{
	}
};

void test_conversion_debug()
{
	try
	{
		const char *origininal_str = "abc";
		XMLPlatformUtils::Initialize();
		VBXML_initialize();

		VBString s, s2;
		VBStringXML sxml;
		const XMLCh *str_xml = sxml.c_xmlStr();

		char xml_str_by_hand[] = { // "abc", origininal_str
			0x61
			,0x00
			,0x62 
			,0x00 
			,0x63 
			,0x00 
			,0x00 // terminator char 1
			,0x00 // terminator char 2
		};

		// const XMLCh *str_xml2 = (XMLCh *)xml_str_by_hand;
		const XMLCh *str_xml2 = sxml.c_xmlStr();
		char *str2 = XMLString::transcode(str_xml2);
		*(str2+3) = 0; // terminator string
		s2 = str2;

		const XMLCh *converted_str = XMLString::transcode(origininal_str);
		const char *str_converted_back = XMLString::transcode(converted_str);
		cout << "str_converted_back=" << str_converted_back << endl;
		const char *converted_str_char = (const char *)converted_str;
		VBAssert(converted_str_char[0]==0x61,"61");
		VBAssert(converted_str_char[1]==0x00,"00_1");
		VBAssert(converted_str_char[2]==0x62,"63");
		VBAssert(converted_str_char[3]==0x00,"00_2");
		VBAssert(converted_str_char[4]==0x63,"63");
		VBAssert(converted_str_char[5]==0x00,"00_3");
		VBAssert(converted_str_char[6]==0x00,"terminator char 1");
		VBAssert(converted_str_char[7]==0x00,"terminator char 2");

		cout << "DEBUG: XMLString::stringLen(converted_str)=" 
			<< XMLString::stringLen(converted_str) << endl;


		VBAssert(XMLString::stringLen((XMLCh *)xml_str_by_hand)==3,"len");

		cout << "DEBUG: XMLString::stringLen((XMLCh *)str_xml)=" 
			<< XMLString::stringLen((const XMLCh *)str_xml) << endl;
		cout << "DEBUG: XMLString::stringLen((XMLCh *)xml_str_by_hand)=" 
			<< XMLString::stringLen((const XMLCh *)xml_str_by_hand) << endl;





		VBBinaryData bd;
		bd.setData(str_xml,3);
		cout << "DEBUG: bd.getStringInHex()=" << bd.getStringInHex() << endl;

		char testdata[] = { 
			0x61
			,0x62
			,0x63 
			,0x65 
			,0x66 
			,0x67 
			,0x68 
			,0x69 
			,0x6a 
			,0x6b 
			,0x6c 
			,0x6d 
		};
		unsigned testDataSize = sizeof(testdata)/sizeof(char);
		bd.setData(testdata,testDataSize);
		bd.dump();
		cout << "DEBUG: bd.getStringInHex()=" << bd.getStringInHex() << endl;


		unsigned len = XMLString::stringLen(str_xml);
		cout << "DEBUG: len=" << len << endl;

		char *str_converted = XMLString::transcode(str_xml);
		cout << "DEBUG: str_converted=" << str_converted << ":" <<  
			*(str_converted)   << *(str_converted+1) << *(str_converted+2) <<
			*(str_converted+3) << *(str_converted+4) << *(str_converted+5) 
			<< "$" << endl;
		char *str_converted_me = XMLString::transcode(sxml.c_xmlStr());
		cout << "DEBUG: str_converted_me=" << str_converted_me << ":" <<  
			*(str_converted_me)   << *(str_converted_me+1) << *(str_converted_me+2) <<
			*(str_converted_me+3) << *(str_converted_me+4) << *(str_converted_me+5) 
			<< "$" << endl;



	}
	catch(VBException_XML & e)
	{
		cout << "VBException_XML: " << e.getExplanation() << endl;
	}
	catch(...)
	{
		cout << "Unhandled Exception" << endl;
	}

}


void test_conversion()
{
	try
	{
		const char *origininal_str = "abc";
		XMLPlatformUtils::Initialize();

		VBXML_initialize();

		VBString s, s2;
		VBStringXML sxml;
		s = origininal_str;
		sxml = t2u(s);
		// cout << "DEBUG: sxml.getStringInHex()=" << sxml.getStringInHex() << endl;
		VBAssert(sxml.getStringInHex()=="6100620063000000","6100620063000000");
		VBAssert(sxml.strLen()==3,"strLen()");

		s2 = u2t(sxml.c_xmlStr());
		// cout << "DEBUG: s2=" << s2 << endl;
		VBAssert(s==s2);


		// XMLCh *str_xml = XMLString::transcode(origininal_str);
		const XMLCh *str_xml = sxml.c_xmlStr();
		// this one does not work, because there exists no object for the return of t2u
		// const XMLCh *str_xml = t2u(origininal_str); 
		VBAssert(*(str_xml+0)==0x61,"61");
		VBAssert(*(str_xml+1)==0x62,"62");
		VBAssert(*(str_xml+2)==0x63,"63");
		VBAssert(*((char*)str_xml+0)==0x61,"61");
		VBAssert(*((char*)str_xml+1)==0x00,"00_1");
		VBAssert(*((char*)str_xml+2)==0x62,"63");
		VBAssert(*((char*)str_xml+3)==0x00,"00_2");
		VBAssert(*((char*)str_xml+4)==0x63,"63");
		VBAssert(*((char*)str_xml+5)==0x00,"00_3");
		VBAssert(*((char*)str_xml+6)==0x00,"terminator char 1");
		VBAssert(*((char*)str_xml+7)==0x00,"terminator char 2");

		XMLPlatformUtils::Terminate();
	}
	catch(VBException_XML & e)
	{
		cout << "VBException_XML: " << e.getExplanation() << endl;
	}
	catch(...)
	{
		cout << "Unhandled Exception" << endl;
	}

}


const char *xmlAsString=
"<?xml version=\"1.0\"?> \n\
<bibliography> \n\
  <book> \n\
    <title>Microelectronics Circuits</title>\n\
    <author>Sedra / Smith</author>\n\
    <editor>HRW Saunders</editor>\n\
    <year>1991</year>\n\
  </book>\n\
  <book> \n\
    <title>Practical Unix Security</title>\n\
    <author>Simson Garfinkel</author>\n\
    <editor>O'Reilly</editor>\n\
    <year>1994</year>\n\
  </book>\n\
</bibliography>\n";


void parse_memory_test()
{
	try
	{
		XMLPlatformUtils::Initialize();
		// VBXML_initialize();

		// XercesDOMParser *parser = new XercesDOMParser;
		auto_ptr<XercesDOMParser>  parser(new XercesDOMParser); 

		// DomErrorReporter *errorHandler= new DomErrorReporter;
		auto_ptr<VBDomErrorReporter> errorHandler(new VBDomErrorReporter); 

		// initialize parser
		parser->setDoNamespaces(false);
		parser->setDoSchema(false);
		parser->setValidationSchemaFullChecking(false);
		parser->setValidationScheme(XercesDOMParser::Val_Never); // XercesDOMParser::Val_Always
		parser->setErrorHandler(errorHandler.get());

		// copy memory to a buffer compatible with Xerces
		VB_XMLMEMBUFFER(buffer,xmlAsString);

		// Parse action. Swallow all data from file
		parser->parse(buffer);

		// get root element from parser
		DOMElement *rootElement = parser->getDocument()->getDocumentElement();

		// process
		VBAssert(getElementValue(rootElement,"book","title")=="Microelectronics Circuits");
		VBString titleStr = getElementValue(rootElement,"book","title");
		VBAssert(titleStr=="Microelectronics Circuits");

		// if using this, produces unhandled exception
		// XMLPlatformUtils::Terminate();

	}
	catch(DOMException & )
	{
		cout << "DOM Exception" << endl;
	}
	catch(VBException_XML & e)
	{
		cout << "VBException_XML: " << e.getExplanation() << endl;
	}
	catch(...)
	{
		cout << "Unhandled Exception" << endl;
	}
}

void xerces_process(DOMElement* rootElement)
{
	const char *titles[] =
	{
		"Microelectronics Circuits"
		,"Practical Unix Security"
	};

	DOMNodeList *bookNodeList = rootElement->getElementsByTagName(t2u("book"));
	unsigned nBooks = bookNodeList->getLength();
	VBAssert(nBooks==2,"there shoule be 2 books in the xml file");
	for (unsigned i=0 ; i < nBooks ; i++)
	{
		if (bookNodeList->item(i)->getNodeType() == 
			DOMNode::NodeType::ELEMENT_NODE)
		{
			DOMElement  *bookElement = (DOMElement*)bookNodeList->item(i);
			DOMNodeList *titleNodeList = 
				bookElement->getElementsByTagName(t2u("title"));
			VBAssert(titleNodeList->getLength()==1,"one title per book");
			if (titleNodeList->item(0)->getNodeType() == 
				DOMNode::NodeType::ELEMENT_NODE)
			{
				DOMElement  *titleElement = (DOMElement*)titleNodeList->item(0);
				VBStringXML titleStr = titleElement->getTextContent();
				VBAssert(u2t(titleStr)==titles[i],"title is wrong");
				// cout << "DEBUG: book title=" << u2t(titleStr) << endl;
			}
		}
	}
}

void VBXML_process(DOMElement* rootElement, deque<Book> & bContainer)
{
	const char *titles[] =
	{
		"Microelectronics Circuits"
		,"Practical Unix Security"
	};
	
	DOMNodeList *bookNodeList = rootElement->getElementsByTagName(t2u("book"));
	unsigned nBooks = bookNodeList->getLength();
	VBAssert(nBooks==2,"there shoule be 2 books in the xml file");
	for (unsigned i=0 ; i < nBooks ; i++)
	{
		VBString title = ::br::com::sbVB::VBXML::
			getNthElementValue(rootElement,"book",i,"title");
		VBAssert(title==titles[i],"title is wrong");
		bContainer.push_back(Book(title,"someAuthor", "someEditor", i));
		// cout << "DEBUG: title=" << title << endl;
	}
}

void parse_file_test_bib()
{
	VBString fileName = "bib.xml";

	if (!::br::com::sbVB::VBLib::fileExist(fileName))
	{
		cout << "file '" << fileName << "' does not exist" << endl;
		exit(1);
	}
	
	deque<Book> bookContainer;
	deque<Book>::iterator it;

	try
	{
		XMLPlatformUtils::Initialize();

		// XercesDOMParser *parser = new XercesDOMParser;
		auto_ptr<XercesDOMParser>  parser(new XercesDOMParser); 

		// DomErrorReporter *errorHandler= new DomErrorReporter;
		auto_ptr<VBDomErrorReporter> errorHandler(new VBDomErrorReporter); 

		parser->setDoNamespaces(FALSE);
		parser->setValidationScheme(XercesDOMParser::Val_Never);
		parser->setErrorHandler(errorHandler.get());

		// Parse action. Swallow all data from file
		parser->parse(fileName);

		///////////////////////////////////////////////////////////////////
		// process parsed data begin
		///////////////////////////////////////////////////////////////////

		// get root element from parser
		DOMElement *rootElement = parser->getDocument()->getDocumentElement();

		xerces_process(rootElement);

		VBXML_process(rootElement,bookContainer);

		///////////////////////////////////////////////////////////////////
		// process parsed data end
		///////////////////////////////////////////////////////////////////
		
	}
	catch(DOMException & )
	{
		cout << "DOM Exception" << endl;
	}
	catch(VBException_XML & e)
	{
		cout << "VBException_XML Exception:" << e.getExplanation() << endl;
	}
	catch(...)
	{
		cout << "Unhandled Exception" << endl;
	}

	XMLPlatformUtils::Terminate();

	/////////////////////////////////////////////////////////////

	cout << "list all elements of bookContainer" << endl;

	// debug add bookContainer
	// bookContainer.push_back(Book("mytitle","myauthor","myeditor",2222));

	for (it = bookContainer.begin(); it != bookContainer.end(); it++)
		cout << "book title=" << it->m_title << endl;
}

void parse_file_test_config()
{
	VBString fileName = "myconfig.xml";

	if (!::br::com::sbVB::VBLib::fileExist(fileName))
	{
		cout << "file '" << fileName << "' does not exist" << endl;
		exit(1);
	}

	try
	{
		{
			XMLPlatformUtils::Initialize();

			// XercesDOMParser *parser = new XercesDOMParser;
			auto_ptr<XercesDOMParser>  parser(new XercesDOMParser); 

			// DomErrorReporter *errorHandler= new DomErrorReporter;
			auto_ptr<::br::com::sbVB::VBXML::VBDomErrorReporter> 
				errorHandler(new VBDomErrorReporter); 

			parser->setDoNamespaces(FALSE);
			parser->setValidationScheme(XercesDOMParser::Val_Never);
			parser->setErrorHandler(errorHandler.get());

			// Parse action. Swallow all data from file
			parser->parse(fileName);

			///////////////////////////////////////////////////////////////////
			// process parsed data begin
			///////////////////////////////////////////////////////////////////

			// get root element from parser
			DOMElement *rootElement = parser->getDocument()->getDocumentElement();

			
			DOMElement *myElement;
			DOMNodeList *myNodeList;
			
			myNodeList = rootElement->getElementsByTagName
				(t2u("userLanguage"));
			
			// if myNodeList is empty
			if (myNodeList->item(0) == 0)
				return;
			
			// if first Node of list is and Element
			if (myNodeList->item(0)->getNodeType() == 
				DOMNode::NodeType::ELEMENT_NODE)
			{
				myElement = (DOMElement*)myNodeList->item(0);
				string str = u2t(myElement ->getTextContent());
				cout << "userLanguage=" << str << endl;
			}


			///////////////////////////////////////////////////////////////////
			// process parsed data end
			///////////////////////////////////////////////////////////////////
		}

		XMLPlatformUtils::Terminate();
	}
	catch(DOMException & )
	{
		cout << "DOM Exception" << endl;
	}
	catch(VBException_XML & e)
	{
		cout << "VBException_XML Exception:" << e.getExplanation() << endl;
	}
	catch(...)
	{
		cout << "Unhandled Exception" << endl;
	}


}


int main()
{
	hello_tests();
	test_conversion();
	test_conversion_debug();
	parse_memory_test();
	parse_file_test_bib();
	parse_file_test_config();

    return 0;
}


